package cn.dengta.webapp.trade.entity;

import java.math.BigDecimal;
import java.util.Date;
import javax.annotation.Nullable;

import cn.dengta.common.util.Common;
import cn.dengta.webapp.base.entity.BaseEntity;
import cn.dengta.webapp.base.entity.TimeBasedEntity;
import cn.dengta.webapp.trade.model.*;
import cn.dengta.webapp.user.entity.User;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import me.codeplayer.util.*;

/**
 * 钻石流水记录表
 *
 * @author yuqidi
 * @since 2022-03-18
 */
@Setter
@Getter
@Accessors(chain = true)
@TableName("tr_user_coin_log")
public class UserCoinLog extends TimeBasedEntity {

	/** 用户ID */
	protected Long userId;
	/** 资金流向：1=收入；0=不变；-1=支出 Flow */
	protected Integer flow;
	/** 交易方：1=from；2=to Side */
	protected Integer side;
	/** 业务类型 TradeType */
	protected String tradeType;
	/** 交易额度 */
	protected Integer tradeAmount;
	/** 资金总额（ <code> = activeAmount + frozenAmount</code> ） */
	protected Integer totalAmount;
	/** 可用余额（含赠送） */
	protected Integer activeAmount;
	/** 冻结金额 */
	protected Integer frozenAmount;
	/** 赠送可用额度 */
	private Integer freePart;
	/** 本次交易使用的免费额度 */
	protected Integer tradeFreePart;
	/** 平台因故（活动、付费方是VIP等）额外支出的【充值】钻石数（直接以充值钻石的性质结算给对应的收益用户） */
	protected Integer platformBonus;
	/** 平台免费增送  赠送活动积分 */
	protected Integer platformFreeBonus;
	/** 目标用户ID */
	protected Long toUserId;
	/** 关联目标类型 */
	protected String assocType;
	/** 关联目标ID */
	protected Long assocId;
	/** 备注 */
	protected String remark;
	/** 添加IP */
	protected String addIp;
	/** 订单号 */
	protected String orderNo;
	/** 处理状态 */
	protected Integer handleStatus;
	protected Long liveId;
	/** Ai标识 */
	protected Long aiId;

	protected transient BaseEntity assocObj;
	protected transient User user;
	/** Ai用户收益汇率 */
	protected transient BigDecimal aiUserIncomeRate;
	/** 延迟收益记录ID */
	private transient Long msgDelayIncomeLogId;

	public UserCoinLog() {

	}

	public static UserCoinLog trade(TradeType tradeType, final boolean fromOrTo, final UserCoin account, final Integer tradeAmount, @Nullable Integer addFreePart) {
		final TradeTypeCore core = fromOrTo ? tradeType.getFrom() : tradeType.getTo();
		CoinConsumePriority priority = tradeType.getCoinConsumePriority();
		if (TradeType.COIN_FOR_REFUND == tradeType) {
			priority = null;
		}
		final UserCoinLog log = new UserCoinLog(account, tradeAmount, priority, core, addFreePart);
		log.setTradeType(tradeType.getValue());
		log.setSide(Side.of(fromOrTo).getValue());
		log.setFlow(core.getFlow().getValue());
		return log;
	}

	/**
	 * 初始化
	 *
	 * @param account 账户
	 * @param changeCoin 改变额度
	 * @param priority 是否优先扣除资金
	 */
	public UserCoinLog(UserCoin account, Integer changeCoin, CoinConsumePriority priority, TradeTypeCore core, @Nullable Integer addFreePart) {
		this.tradeAmount = core.isConsume() ? -changeCoin : changeCoin;

		if (priority != null) {
			Assert.isTrue(addFreePart == null || addFreePart == 0);

			final int usedFree;
			switch (priority) {
				case ACTIVE_FIRST: // 优先使用真实资金
					usedFree = Math.max(changeCoin - (account.getActiveAmount() - account.getFreePart()), 0);
					break;
				case FREE_FIRST: // 优先使用免费资金
					usedFree = Math.min(account.getFreePart(), changeCoin);
					break;
				default:
					throw new UnsupportedOperationException();
			}
			this.freePart = account.opFreePart('-', usedFree);
			this.tradeFreePart = -usedFree;
		} else if (addFreePart != null && addFreePart != 0) {
			this.freePart = account.opFreePart('+', addFreePart);
			this.tradeFreePart = addFreePart;
		} else {
			this.freePart = account.getFreePart();
			this.tradeFreePart = 0;
		}

		this.totalAmount = account.opTotalAmount(core.operators[0], changeCoin);
		this.activeAmount = account.opActiveAmount(core.operators[1], changeCoin);
		this.frozenAmount = account.opFrozenAmount(core.operators[2], changeCoin);

	}

	public TradeType getTradeTypeE() {
		return TradeType.of(tradeType);
	}

	public String getTradeType_() {
		return X.map(getTradeTypeE(), TradeType::getLabel);
	}

	public TradeTypeCore getCoreType() {
		return X.map(getTradeTypeE(), t -> t.getCoreType(side));
	}

	public char getSign() {
		return getCoreType().getSign();
	}

	public void handleAssocObject(BaseEntity obj) {
		this.assocObj = obj;
		this.assocType = obj.entityName();
		this.assocId = obj.getId();
	}

	/** 是否AI */
	public boolean hasAi() {
		return Cmp.gt(this.aiId, 0);
	}

	public static String fragment(UserCoinLog log) {
		return log.getAssocId() + Common.SEP
				+ Math.abs(log.getTradeAmount()) + Common.SEP
				+ Math.abs(log.getTradeFreePart()) + Common.SEP
				+ Math.abs(log.getPlatformBonus()) + Common.SEP
				+ Math.abs(log.getPlatformFreeBonus()) + Common.SEP
				+ log.getTradeType() + Common.SEP
				+ log.getId();
	}

	public static String fragment(long assocId, int totalCoin, int freePart, int platformBonus, int platformFreeBonus, TradeType tradeType) {
		return assocId + Common.SEP + totalCoin + Common.SEP + freePart + Common.SEP + platformBonus + Common.SEP + platformFreeBonus + Common.SEP + tradeType + Common.SEP + 0;
	}

	/**
	 * 解析交易记录核心片段
	 *
	 * @return {@code [ 关联对象ID, 交易钻石总数, 其中免费钻石数, 平台补贴钻石总数, 其中平台补贴免费钻石数, 类型, UserCoinLogId, 可能的添加时间 ] }
	 */
	public static Object[] resolve(String fragment) {
		final String[] parts = fragment.split(",");
		final Object[] result = new Object[parts.length];
		for (int i = 0; i < result.length; i++) {
			result[i] = parts[i];
		}
		return result;
	}

	public static UserCoinLog resolve(Object[] info) {
		final UserCoinLog log = new UserCoinLog();
		log.assocId = NumberUtil.getLong(info[0]);
		log.tradeAmount = NumberUtil.getInt(info[1]);
		log.tradeFreePart = NumberUtil.getInt(info[2]);
		log.platformBonus = NumberUtil.getInt(info[3]);
		log.platformFreeBonus = NumberUtil.getInt(info[4]);
		log.tradeType = StringUtil.toString(info[5]);
		log.id = NumberUtil.getLong(info[6]);
		if (info.length > 7) {
			log.addTime = new Date(NumberUtil.getLong(info[7]));
		}
		if (info.length > 8) {
			log.msgDelayIncomeLogId = NumberUtil.getLong(info[8]);
		}
		return log;
	}

	public static final String USER_ID = "user_id";
	public static final String TRADE_TYPE = "trade_type";
	public static final String ORDER_NO = "order_no";
	public static final String FLOW = "flow";
	public static final String LIVE_ID = "live_id";
	public static final String SIDE = "side";
	public static final String TRADE_AMOUNT = "trade_amount";
	public static final String TOTAL_AMOUNT = "total_amount";
	public static final String ACTIVE_AMOUNT = "active_amount";
	public static final String FROZEN_AMOUNT = "frozen_amount";
	public static final String FREE_PART = "free_part";
	public static final String TRADE_FREE_PART = "trade_free_part";
	public static final String TO_USER_ID = "to_user_id";
	public static final String ASSOC_TYPE = "assoc_type";
	public static final String ASSOC_ID = "assoc_id";
	public static final String REMARK = "remark";
	public static final String HANDLE_STATUS = "handle_status";
	public static final String ADD_IP = "add_ip";

}
